13. Using modelflow with World Bank models

The Modelflow python package has been developed to solve a wide range of models, see the modelflow gibhub web site for working examples of the Solow Model, the FR/USB model and others.

The package has been substantially expanded to include special features that enable it to work with World Bank models originally developed in EViews and designed to use EViews Model Object for simuation.

This chapter illustrates how to access these models, how to load them into a modelflow anaconda environment on your computer and how to perform a variety of simulations

14. Accessing a world bank model

At this time several World bank macrostructural models are available to download and use with modelflow. These include a macrostructural model for:

  • Indonesia

  • Nepal

  • Croatia

  • Iraq

  • Kenya

  • Bolivia

Each of these models has been developed as part of the outreach work of the World Bank. The basic modelling framework of each of these models is outlined in {cite:p :burns_World_2019} with specific extensions reflecting features of the individual country modelled.

This book uses as an example a climate aware model for Pakistan developed in 2020 and described in {cite:p :burns_climate_2021 }.

The World Bank models are distributed in the pcim file format of the modelflow and can be downloaded by right clicking on the links above. The Pakistan model can be downloaded here by right clicking on the above link and selecting Save Link as and placing the file on a directory accessible by your modelflow installation.

15. Preparing your python environment

As always, the modelflow and other python packages that will be used need to be imported into your python session. The examples here and this book were written and solved in a Jupyter Notebook. There are some Jupyter specific commands included in these examples and these are annotated. However, the bulk of the content of the programs can be run in other environments, including Interactive Development Environments (IDE) like Spyderor MS Visual Code. All the programs have been tested under spyder as well as Jupyter Notebook.

It is assumed that:

  1. you have already installed modelflow and its various support packages following the instructions in Chapter xx

  2. you are using Anaconda, and that

  3. you have activated your modelflow environment by executing the following command from your python command line:

conda activate modelflow

where modelflow is the name you have given to the conda environment into which you installed modelflow.

# import the model class from modelflow package
from modelclass import model 
import modelmf       # Add useful features to pandas dataframes 
                     # using utlities initially developed for modelflow

model.widescreen()   # These modelflow commands ensure that outputs from modelflow play well with Jupyter Notebook
model.scroll_off()

%load_ext autoreload   
%autoreload 2

16. Working with PakMod under modelflow

The basic method for working with any model is the same. Indeed the initial steps followed here are the same as were followed during the simple model discussion.

Process:

  1. Prepare the workspace

  2. Load the model Modelflow

  3. Design some scenarios

  4. Simulate the model

  5. Visualize the results

16.1. Load a pre-existing model, data and descriptions

To load a model use the model.modelload() method of modelflow.

The command below

mpak,bline = model.modelload('M:\modelflow\modelflow-manual\papers\mfbook\content\models\pak.pcim', alfa=0.7,run=1,keep= 'Baseline')

instantiates (creates an instance of) a model object and assigns it to the variable name mpak. The run=1 option executes the model and assigns the result of the model execution to the dataframe baseline. The model is solved with the parameter alfa set to 0.7. The \(alfa \in (0,1)\) parameter determines the step size of the solution engine. The larger alfa the larger the step size. Larger step sizes solve faster, but may have trouble finding a unique solution. Smaller step sizes take longer to solve but are more likely to find a unique solution. Values of alfa=.7 work well for World Bank models.

#Replace the path below with the location of the pak.pcim file on your computer
mpak,baseline = model.modelload('M:\modelflow\modelflow-manual\papers\mfbook\content\models\pak.pcim', \
                                alfa=0.7,run=1,keep= 'Baseline')
file read:  C:\Users\wb268970\OneDrive - WBG\Ldrive\MFM\modelflow\modelflow-manual\papers\mfbook\content\models\pak.pcim

The keep option instructs modelflow to maintain in the model object (mpak) the results of the intitial scenario, assigning it the text name Baseline.

Note

the variable bline contains the dataframe with the results of the simulation. This is distinct from the data that is stored by the kept= command. That said, the data associated with each, while stored separately, have the same numerical values.

16.2. Variables in World Bank models

A typical World Bank model will have in excess of 300 variables. Each has a mnemonic that is structured in a specific way, The root for almost all are 14 characters long (some special variables have additional characters appended to this root) (see discussion in section).


12345678901234
CCCAAMMMNNNNUC

where:

Letters

Meaning

CCC

The three-leter ISO code for a country – i.e. IDN for Indonesia, RUS for Russia

AA

The two-letter major accounting system to which the variable attaches, i.e. NY means National Income Accounts (see below for others)

MMM

The three-letter major sub-category of the data - i.e. GDP, EXP - expenditure

NNNN

The minor sub-category - MKTP for market prices

U

The measure (K: real variable;C: Current Values; X: Prices)

C

denotes the Currency (N: National currency; D: USD; P: PPP)

Common Accounting systems include

Code

Meaning

NY

National income

NE

National expenditure Accounts

NV

Value added accounts

GG

General Government Accounts

BX

Balance of Payments: Exports

BM

Balance of Payments: Imports

BN

Balance of Payments: Net

BF

Balance of Payments: Financial Account

Thus

Mnemonic

Meaning

IDNNYGDPMKTPKN

Indonesia GDP at market prices, real in Indonesian Rupiah

KENNECPNPRVTXN

Kenya Private (household) consumption expenditure schillings deflator

BOLGGEXPGNFSCN

Bolivia Government Expenditure on Goods and services (GNFS) in current Bolivars

HRVGGREVDCITCN

Croatia Government Revenues Direct Corporate Income Taxes in current Euros

NPLBXGSRNFSVCD

Nepal BOP Exports of non-factor services from the goods and services accounts in current USD

16.3. Extract a list of variables

To extract a list of all variables matching a pattern, we can use the names function. Below we ask for a list of all variables for PAKistan National Expenditure accounts CONsumption Xprice deflators N in local currency.

Note

Wildcards The * in the command mpak['PAKNECON*XN'].names is a wildcard character and the extopression will return all variables that begin PAKNECON and end XN. the ? is another wildcard expression. It will match only single characters. Thus mpak['PAKNECONPRVT?N'].names would return three variables: PAKNECONPRVTKN, PAKNECONPRVTXN, and PAKNECONPRVTXN. The real, current value, and deflators for household consumption expenditure.

mpak['PAKNECON*XN'].names
['PAKNECONENGYXN', 'PAKNECONGOVTXN', 'PAKNECONOTHRXN', 'PAKNECONPRVTXN']
mpak['PAKNECONPRVT?N'].names
['PAKNECONPRVTCN', 'PAKNECONPRVTKN', 'PAKNECONPRVTXN']

17. Behavioural equations in the MFMod framework

Recall a behavioural equation determine the value of an endogenous variable. For many of the variables in Wold Bank models, behavioural functions are estimated using an Error Correction Framework that splits the equation into a theoretically determined long run component and a more idiosyncratic short-run component.

17.1. The ECM specification

The ECM approach addresses the above challenge by modelling both the long run relationship and the short run short run behaviour and bringing them together into one equation.

The ECM specification is therefore a single equation comprised of two parts (the long run relationship, and the short-run relationship).

Consider as an example two variables say consumption and disposable income. Both have an underlying trend or in the parlance are co-integrated to degree 1. For simplicity we call them y an x.

17.1.1. The short run relationship

In its simplest form we might have a short run relationship between the growth rates of our two variables such that:

\[ \Delta log(Y_t) = \alpha + \beta \Delta log(X_t) +\epsilon_t \]

or substituting lower case letters for the logged values.

\[ \Delta y_t = \alpha + \beta \Delta x_t +\epsilon_t \]

17.1.2. The long run equation

The long run relates the level of the two (or more) variables. We can write a simple version of that equation as:

\[ Y_t=αX_t^β+ \eta_t \]

Rewriting this (in logarithms) it can be expressed as:

\[ y_t = ln⁡(α) + βy_t + \eta_t \]

17.2. The long run equation in the steady state

First we note that in the steady state the expected value of the error term in the long run equation is zero (\(\eta_t=0 \)) so in those conditions we can simplify the long run relationship to:

\[y_t=ln⁡(α)+\beta x_t\]

or equivalently (substituting A for the log of \(\alpha\)).

\[y_t-A-βx_t=0\]

Moreover if we multiplied this by some arbitrary constant say \(-\lambda\) it would still equal zero.

\[-\lambda(y_t -A-βx_t)\]

and in the steady state this will also be true for the lagged variables

\[-\lambda(y_{t-1-} A - βx_{t-1})\]

17.3. Putting it together

From before we have the short run equation:

\[ \Delta y_t = \alpha + \beta \Delta x_t +\epsilon_t \]

Inserting our steady state expression into the short run equation makes no difference (in the long run) because in the long run it is equal to zero.

\[ \Delta y_t = -\lambda(y_{t-1-}A-βx_{t-1}) + \alpha + \beta \Delta x_t +\epsilon_t \]

When we are not in the steady state the expression \( y_{t-1}-A-βx_{t-1} \) is of course the error term from the long run equation (a measure of how far we are away from equilibrium).

17.3.1. Lamda, the speed of adjustment

We can then interpret the parameter $\( \lambda \)\( as the speed of adjustment. As long as \)\lambda\( is greater than zero and less or equal to one if there are no further disturbances ( \)\epsilon_t=0\() the expression multiplied by lambda will slowly decline toward zero. How fast depends on how large or small is \)\(\lambda\)$.

To be convergent \(\lambda\) must be between 0 and 1, if its is negative or greater than one, then the long run portion of the equation will cause the disequilibrium to grow each period (\(\lambda >1) not diminish or oscillate from positive to negative (\)\lambda <0$).

Intuitively, the long run error term measures how far we are from equilibrium one period earlier (at t-1). The ECM term ensures that we will slowly converge to equilibrium – the point at which the long run equation holds exactly. If $\(\lambda\)\( is greater than zero but less than one (or equal to one) some portion of the previous period year's disequilibrium will be absorbed each year. How much is absorbed depends on the size of estimated speed of the adjustment coefficient \)\lambda$.

Looking at an ECM equation we can then break it up into its component parts. For the consumption function it will look something like this:

\[ \Delta c_t = -\lambda (\underbrace{ log(C_{t-1})-log(Wages_{t-1}-Taxes_{t-1}+Transfers_{t-1} + \alpha)} _\text{Long run} +\beta \underbrace{\Delta y_t}_\text{short run}\]

If we look at the equation for consumption in mpak we see that it follows something very close to this formulation.

mpak.PAKNECONPRVTKN.frml
Endogeneous: PAKNECONPRVTKN: Household Consumption
Formular: FRML <Z,EXO> PAKNECONPRVTKN = (PAKNECONPRVTKN(-1)*EXP(-PAKNECONPRVTKN_A+ (-0.2*(LOG(PAKNECONPRVTKN(-1))-LOG((PAKNYYWBTOTLCN(-1)*(1-PAKGGREVDRCTXN(-1)/100))/PAKNECONPRVTXN(-1)))+1*((LOG((PAKNYYWBTOTLCN*(1-PAKGGREVDRCTXN/100))/PAKNECONPRVTXN))-(LOG((PAKNYYWBTOTLCN(-1)*(1-PAKGGREVDRCTXN(-1)/100))/PAKNECONPRVTXN(-1))))+0.0303228629698929+0.0163839011059956*DURING_2010-0.3*(PAKFMLBLPOLYXN/100-((LOG(PAKNECONPRVTXN))-(LOG(PAKNECONPRVTXN(-1)))))) )) * (1-PAKNECONPRVTKN_D)+ PAKNECONPRVTKN_X*PAKNECONPRVTKN_D  $

PAKNECONPRVTKN  : Household Consumption
DURING_2010     : 
PAKFMLBLPOLYXN  : Policy Rate
PAKGGREVDRCTXN  : Effective tax rates
PAKNECONPRVTKN_A: Add factor:Household Consumption
PAKNECONPRVTKN_D: Exo dummy:Household Consumption
PAKNECONPRVTKN_X: Exo value:Household Consumption
PAKNECONPRVTXN  : Household demand
PAKNYYWBTOTLCN  : Economy-wide wage bill

Remember the .frml method presents the economic equation in a normalized form.

(PAKNECONPRVTKN(-1)EXP(-PAKNECONPRVTKN_A+ (-0.2(LOG(PAKNECONPRVTKN(-1))-LOG((PAKNYYWBTOTLCN(-1)(1-PAKGGREVDRCTXN(-1)/100))/PAKNECONPRVTXN(-1)))+1((LOG((PAKNYYWBTOTLCN*(1-PAKGGREVDRCTXN/100))/PAKNECONPRVTXN))-(LOG((PAKNYYWBTOTLCN(-1)(1-PAKGGREVDRCTXN(-1)/100))/PAKNECONPRVTXN(-1))))+0.0303228629698929+0.0163839011059956DURING_2010-0.3*(PAKFMLBLPOLYXN/100-((LOG(PAKNECONPRVTXN))-(LOG(PAKNECONPRVTXN(-1)))))) )) * (1-PAKNECONPRVTKN_D)+ PAKNECONPRVTKN_X*PAKNECONPRVTKN_D $

Taking logarithms of both sides of the the first expression (excluding the *(1-PAKNECONPRVTKN_D) term) and collecting the PAKNECONPRVTKNs onm teh left-hand side , we can recover the originally estimated ECM expression, where we simplify the mnemonics to ease reading of the equation using:

Model Mnemonic

Simplified

Meaning

PAKNECONPRVTKN

\(CON^{KN}_t\)

Household Consumption

DURING_2010

\(D^{2010}_t\)

A dummy

PAKFMLBLPOLYXN

\(r^{policy}_t\)

Policy Rate

PAKGGREVDRCTXN

\(DirectTxR_t\)

Direct Taxes: Effective rate

PAKNECONPRVTKN_A

\(CON^{KN_AF}_t\)

Add factor:Household Consumption

PAKNECONPRVTXN

\(CON^{XN}_t\)

Household Consumption deflator

PAKNYYWBTOTLCN

\(WAGEBILL^{CN}_t\)

Economy-wide wage bill

\[\Delta log(CON^{KN}_t) = -0.2*\bigg[LOG(CON^{KN}_{t-1})-LOG\bigg({{WAGEBILL^{CN}_{t-1}*(1-DirectTxR_{t-1}/100)} \over {CON^{XN}_{t-1}}}\bigg)\bigg] + 1.0*\Delta log \bigg( {{WAGEBILL^{CN}_{t}*(1-DirectTxR_{t}/100)} \over {CON^{XN}_{t}}}\bigg)\]
\[+0.030 + 0.016*D^{2010}_t-0.3*\bigg(r^{policy}_t/100-\Delta log(CON^{XN}_{t})\bigg) -CON^{KN_AF}_t \]

Where in this instance the short-run elasticity of consumption to disposable income has been constrained to 1, and teh short run elasticitya of consumption to the real interest rate is 0.3.

Charl: Something goofy here. It looks like the SR has income elasticity of one imposed – probably why simulations are so jerky. This would be a better example if we has SR elasticity less than one. Any reason we can’t build this with a less onerous assumption?

18. Scenario analysis

An essential feature of a model is that when given a specific set of inputs (the exogenous variables to the model) it will always return the same results. As noted when, as was the case of the load, the model is solved without changing any inputs we would expect that the model will return exactly the same data as before. To test this for mpak we can compare the results from the simulation using the basedf and lastdf dataframes.

Below we are gratified to see that the percent difference between the variables in the two dataframes following a simulation where the inputs were not changes is zero.

# Need statement to change the default format
mpak.smpl(2020,2030)
mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN'].difpctlevel.mul100.df
PAKNYGDPMKTPKN PAKNECONPRVTKN
2020 0.0 0.0
2021 0.0 0.0
2022 0.0 0.0
2023 0.0 0.0
2024 0.0 0.0
2025 0.0 0.0
2026 0.0 0.0
2027 0.0 0.0
2028 0.0 0.0
2029 0.0 0.0
2030 0.0 0.0

18.1. Different kinds of simulations

The modelflow package allows us to do 4 different kinds of simulations:

  1. A shock to an exogenous variable in the model

  2. An exogenous shock of a behavioural variable, executed by exogenizing the variable

  3. An endogenous shock of a behavioural variable, executed by shocking the add factor of the variable.

  4. A mixed shock of a behavioural variable, achieved by temporarily exogenixing the variable.

Although technically modelflow would allow us to shock identities, that would violate their nature as accounting rules so we exclude this possibility.

18.1.1. A shock to an exogenous variable

A World Bank model will reproduce the same values if inputs (exogenous variables) are not changed. In the simulation below we change the oil price increasing it by $25 for the three years between 2025 and 2027 inclusive.

To do this we first create a new input dataframe with the revised data.

Then we use the mfcalc method to change the value for the three years in question.

Finally we do a but of pandas math to display the initial value, the changed value and the difference between the two, confirming that the mfcalc statement did what we hoped.

#Make a copy of the baseline dataframe
oilshockdf=mpak.basedf
oilshockdf=oilshockdf.mfcalc("<2025 2027> WLDFCRUDE_PETRO = WLDFCRUDE_PETRO +25")

compdf=mpak.basedf.loc[2000:2030,['WLDFCRUDE_PETRO']]
compdf['LASTDF']=oilshockdf.loc[2000:2030,['WLDFCRUDE_PETRO']]
compdf['Dif']=compdf['LASTDF']-compdf['WLDFCRUDE_PETRO']
compdf
WLDFCRUDE_PETRO LASTDF Dif
2000 28.229719 28.229719 0.0
2001 24.351825 24.351825 0.0
2002 24.927748 24.927748 0.0
2003 28.898903 28.898903 0.0
2004 37.733388 37.733388 0.0
2005 53.391025 53.391025 0.0
2006 64.288259 64.288259 0.0
2007 71.116559 71.116559 0.0
2008 96.990454 96.990454 0.0
2009 61.756922 61.756922 0.0
2010 79.040772 79.040772 0.0
2011 104.009398 104.009398 0.0
2012 105.009629 105.009629 0.0
2013 104.077497 104.077497 0.0
2014 96.235000 96.235000 0.0
2015 50.752778 50.752778 0.0
2016 42.811667 42.811667 0.0
2017 52.805000 52.805000 0.0
2018 56.070279 56.070279 0.0
2019 59.537471 59.537471 0.0
2020 63.219063 63.219063 0.0
2021 67.128311 67.128311 0.0
2022 71.279294 71.279294 0.0
2023 75.686960 75.686960 0.0
2024 80.367180 80.367180 0.0
2025 85.336809 110.336809 25.0
2026 90.613742 115.613742 25.0
2027 96.216983 121.216983 25.0
2028 102.166709 102.166709 0.0
2029 108.484346 108.484346 0.0
2030 115.192643 115.192643 0.0

18.1.2. Running the simulation

Having created a new dataframe comprised of all the old data plus the changed data for the oil price we can execute the simulation. In the command below, the simulation is run from 2020 to 2040, using the oilshockdf as the input dataframe. The results of the simulation will be put into a new dataframe ExogOilSimul. The Keep command ensures that the mpak model object stores (keeps) a copy of the results identified by the text name ‘$25 increase in oil prices 2025-27’.

ExogOilSimul = mpak(oilshockdf,2020,2040,keep='$25 increase in oil prices 2025-27') # simulates the model 

Using the modelflow visualization tools we can see the impacts of the shock; as a print out; as charts and within Jupyter notebook as an interactive widget.

18.1.2.1. Results

Here we confirm that the shock we wanted to introduce was executed. The dif.df method returns the difference between the selected variable(s) as a dataframe, the smpl method restructs the time period of over which subsequent commands are effectuated.

mpak.smpl(2020,2030)
mpak['WLDFCRUDE_PETRO'].dif.df
WLDFCRUDE_PETRO
2020 0.0
2021 0.0
2022 0.0
2023 0.0
2024 0.0
2025 25.0
2026 25.0
2027 25.0
2028 0.0
2029 0.0
2030 0.0

Below we look at the impact of this change on a few variables, expressed as a percent deviation of the variable from its pre-shock level.

The first variable PAKNYGDPMKTPKN is Pakistan’s real GDP, the second PAKNECONPRVTKN is real consumption and the third is the Consumer price deflator PAKNECONPRVTXN.

mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN PAKNEIMPGNFSKN PAKNECONPRVTXN'].difpctlevel.mul100.plot(Title="Impact of temporary $25 hike in oil prices")
../../_images/LoadingWBModel_28_0.png

The graphs show the change in the level as a percent of the previous level. The graphs suggest that a temporary $25 oil price hike would reduce GDP in the first year by about 1.5 percent, that the impact would diminish in the second year to about -.25 percent and that the impact would turn positive in the fourth year when the price effect was eliminated.
The negative impact would on household consumption would be stronger but follow a similar pattern. The reason that the GDP impact is smaller, is partly because of the impact on imports which decline strongly. Because imports enter into the GDP identity with a negative sign they reduce the overall impact on GDP.

Finally as could be expected prices rise sharply initially with higher oil prices, but as the slow down in growth is felt, inflationary pressures turn negative and the overall impact on the price level turns negative. The graph above shows what is happening to the price level. To see the impact on inflation (the rate of growth of prices) we will have to do a separate graph using difpct.mul100, which shows teh change in the rate of growth of variables where the growth rate is expressed as a per cent.

mpak['PAKNECONPRVTXN'].difpct.mul100.plot(Title="Change in inflation from a temporary $25 hike in oil prices")
../../_images/LoadingWBModel_30_0.png

This view, gives a more nuanced result. Inflation spikes initially by about 1.2 percent, but falls below as the influence of the slowdown weighs on the lagged effect of higher oil prices. In 2028 when oil prices drop back to their previous level this adds to the dis-inflationary forces in the economy at first, but the boost to demand fro lower prices soon translates into an acceleration in growth and higher inflation.

18.2. An exogenous shock to a Behavioural variable

Behavioural equations can be de-activated by exogenizing them, either for the entire simulation period, or for a selected sub period. In this example we exogenize consumption for the entire simulation period.

To motivate the simulation we assume that a change in weather patterns has increased the number of sunny days by 10 percent which has increased households happiness and therefore causes them to permanently increase their spending by 2.5% beginning in 2025.

We can do so either by manually or use the method .fix(). For simplicity we will use .fix() and we will explain the manual steps that .fix() does for us.

To exogenize PAKNECONPRVTKN for the entire simulation period we will first create a new dataframe as a slightly modified version of our basedf.

Cfixed=mpak.fix(mpak.basedf,PAKNECONPRVTKN)

This does two things, that we could have done manually. First it sets the dummy variable PAKNECONPRVTKN_D=1 for the entire simulation period – effectively transforming the equation to PAKNECONPRVTKN=PAKNECONPRVTKN_X. Then it sets the variable PAKNECONPRVTKN_X in the Cfixed dataframe equal to the value of PAKNECONPRVTKN in the basedf dataframe. All the other variables are just copies of their values in basedf.

With PAKNECONPRVTKN_D=1 throughout the normal behavioural equation is effctively de-activated or exogenized.

mpak.smpl() # reset the active sample period to the full model.
Cfixed=mpak.fix(baseline,'PAKNECONPRVTKN')
Cfixed=Cfixed.mfcalc("<2025 2040> PAKNECONPRVTKN_X = PAKNECONPRVTKN_X*1.025")

Having made this change we can solve the model, by passing it the new CFixed dataframe.

````CFixedRes = mpak(Cfixed,2020,2040,keep=’2.5% increase in C 2025-40’) # simulates the model ```

CFixedRes = mpak(Cfixed,2020,2040,keep='2.5% increase in C 2025-40') # simulates the model 
mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN PAKNEIMPGNFSKN PAKNECONPRVTXN'].difpctlevel.mul100.plot(Title="Impact of temporary $25 hike in oil prices")
../../_images/LoadingWBModel_37_0.png
with mpak.set_smpl(2020,2040):
    print(mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN PAKNEIMPGNFSKN PAKNECONPRVTXN'].difpctlevel.mul100.df)
      PAKNYGDPMKTPKN  PAKNECONPRVTKN  PAKNEIMPGNFSKN  PAKNECONPRVTXN
2020    2.019308e-08        0.000000    2.808458e-08    1.841915e-08
2021   -3.899954e-10        0.000000   -7.528570e-10    8.995251e-09
2022   -4.075578e-09        0.000000    7.531269e-09    1.598160e-08
2023    8.030444e-09        0.000000    2.254740e-08    2.550616e-08
2024   -3.040945e-09        0.000000    3.364358e-08    4.579471e-08
2025    1.857821e+00        2.500000    2.111848e+00    6.547200e-01
2026    1.838869e+00        2.500000    2.294774e+00    1.600744e+00
2027    1.723747e+00        2.500000    2.558362e+00    2.608787e+00
2028    1.557530e+00        2.500000    2.919366e+00    3.608118e+00
2029    1.369944e+00        2.500000    3.367783e+00    4.563919e+00
2030    1.173879e+00        2.500000    3.876162e+00    5.450966e+00
2031    1.801835e-01        1.379063    3.474070e+00    5.958611e+00
2032   -4.200807e-01        0.766517    3.436773e+00    6.078175e+00
2033   -6.087119e-01        0.634926    3.727205e+00    5.965989e+00
2034   -5.874626e-01        0.705209    4.098433e+00    5.750784e+00
2035   -5.214086e-01        0.775985    4.373174e+00    5.490850e+00
2036   -4.690272e-01        0.789340    4.507495e+00    5.203244e+00
2037   -4.311355e-01        0.761726    4.524331e+00    4.894436e+00
2038   -3.945717e-01        0.722178    4.460112e+00    4.573111e+00
2039   -3.516112e-01        0.687414    4.342588e+00    4.250741e+00
2040   -3.019698e-01        0.661382    4.189132e+00    3.938522e+00

The permanent rise in consumption by 2.5 percent causes a temporary increase in GDP of close to 2% (1.86). Higher imports tend to diminish the effect on GDP, while over time higher prices due to the inflationary pressures caused by the additional demand cause the GDP impact to diminish to close to zero by th end of the sample period.

18.3. Temporarily exogenize a behavioural variable

The third method of formulating a scenario involves temporarily exogenizing a variable. The methodology is the same except the period for which the variable is exogenized is different.

To fully explore the differences in the approaches, we will do three scenarios.

  1. We exogenize the variable for the whole period, but shock it for three years (2025-2027).

  2. We exogenize the variable for the whole period, but shock it for three years (2025-2027)– but use the –kg option to keep the growth rates of the exogenized variable the same in the post-shock period

  3. We exogenize the variable only for the period during which we shock the dependent variable (2025-2027)

18.3.1. Temporary shock exogenized for the whole period

Here the set up is basically the same as before.

mpak.smpl() # reset the active sample period to the full model. Cfixed=mpak.fix(baseline,’PAKNECONPRVTKN’)

mpak.smpl() # reset the active sample period to the full model.
CTempExogAll=mpak.fix(baseline,'PAKNECONPRVTKN')
CTempExogAll=CTempExogAll.mfcalc("<2025 2027> PAKNECONPRVTKN_X = PAKNECONPRVTKN*1.025")

#Now we solve the model
CTempXAllRes = mpak(CTempExogAll,2020,2040,keep='2.5% increase in C 2025-27 -- exog whiole period') # simulates the model 
mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN PAKNEIMPGNFSKN PAKNECONPRVTXN'].difpctlevel.mul100.plot(Title="Impact of temporary $25 hike in oil prices")
../../_images/LoadingWBModel_41_0.png

Here the results are quite different. GDP is boosted initially as before but when consumption drops back to its pre-shock level, GDP and imports decline sharply.

Prices (and inflation) are higher initially but when the economy starts to slow after 2025 prices start to fall (disinflation).

18.3.2. Temporary shock exogenized for the whole period

In this scenario we do exactly the same as in the previous but we use the –KG option in the mfcalc to maintain the pre-shock growth rates of consumption in the post-shock period.

The set up is identical to the rpeceiding simulation except for the additional –kg optionin the mfcalc call.

mpak.smpl() # reset the active sample period to the full model.
CTempExogAllKG=mpak.fix(baseline,'PAKNECONPRVTKN')
CTempExogAllKG=CTempExogAllKG.mfcalc("<2025 2027> PAKNECONPRVTKN_X = PAKNECONPRVTKN_X*1.025 --kg")

#Now we solve the model
CTempXAllResKG = mpak(CTempExogAllKG,2020,2040,keep='2.5% increase in C 2025-27 -- exog whole period --keep_growth=TRUE') # simulates the model 
mpak['PAKNYGDPMKTPKN PAKNECONPRVTKN PAKNEIMPGNFSKN PAKNECONPRVTXN'].difpctlevel.mul100.plot(Title="2.5% boost o cons 2025-27 --keep growth=true")
../../_images/LoadingWBModel_44_0.png
alternative = alternative_base.upd(f'<2023 2023> PAKGGREVGNFSCN_X + {baseline.loc[2023,"PAKNYGDPMKTPCN"]*0.01 }')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [18], in <cell line: 1>()
----> 1 alternative = alternative_base.upd(f'<2023 2023> PAKGGREVGNFSCN_X + {baseline.loc[2023,"PAKNYGDPMKTPCN"]*0.01 }')

NameError: name 'alternative_base' is not defined

The variable before and after the shock can be displayed

print(f'Value of GDP in 2023: {baseline.loc[2023,"PAKNYGDPMKTPCN"]:,.0f}')
print(f'Base value in 2023: {alternative_base.loc[2023,"PAKGGREVGNFSCN_X"]:,.0f}. Alternative value: {alternative.loc[2023,"PAKGGREVGNFSCN_X"]:,.0f}.'
    f'Difference: {-(alternative_base.loc[2023,"PAKGGREVGNFSCN_X"]-alternative.loc[2023,"PAKGGREVGNFSCN_X"]):,.0f}.')

18.4. Simulate the model

%matplotlib notebook 
result = mpak(alternative,2020,2035,keep='Taxes on Goods and Services up by 1 pct of GDP in 2023') # simulates the model 

18.5. Access results

Now we have two dataframes with results baseline and result. These dataframes can be manipulated and visualized with the tools provided by the pandas library and other like Matplotlib and Plotly. However to make things easy the first and latest simulation result is also in the mpak object:

  • mpak.basedf: Dataframe with the values for baseline

  • mpak.lastdf: Dataframe with the values for alternative

The result can easily be visualized in Jupyter notebooks by using the [.] operator this will display the values of the variables in square brackets and useful transformations of the values including the impact. In addition the exotenous variables which has changed are displayed.

Click on the tabs to display the different output

mpak['PAKNYGDPMKTPCN PAKNYGDPMKTPKN PAKGGEXPTOTLCN PAKGGREVTOTLCN PAKNECONGOVTKN']

18.6. Or use keep_plot to make more bespoken charts which can be saved in many formats

This method can display a number of different transformations of the series for more here
Here only a few:

18.6.1. Differences of growth rates

mpak.keep_plot('PAKNYGDPMKTPCN PAKGGEXPTOTLCN',diff=1,showtype='growth',savefig='testgraph/tax_impact_growth_.svg',legend=0);

18.6.2. Differences in percent of baseline values

mpak.keep_plot('PAKNYGDPMKTPCN PAKGGEXPTOTLCN',diffpct=1,showtype='level',savefig='testgraph/tax_impact_difpct_.svg',legend=0);

18.7. Some variations on keep_plot(

The variables we want to be displayed is listed as first argument. Variable names can include wildcards (using * for any string and ? for any character)

Transformation of data displayed:

showtype=

Use this operator

‘level’ (default)

No transformation

‘growth’

The growth rate in percent

‘change’

The yearly change (\(\Delta\))

legend placement

legend=

Use this operator

False (default)

The legends will be placed at the end of the corresponding line

True

The legends are places in a legend box

Often it is useful to compare the scenario results with the baseline result. This is done with the diff argument.

diff=

Use this operator

False (default)

All entries in the keep_solution dictionary is displayed

True

The difference to the first entry is shown.

It can also be useful to compare the scenario results with the baseline result measured in percent. This is done with the diffpct argument.

diffpct=

Use this operator

False (default)

All entries in the keep_solution dictionary is displayed

True

The difference in percent to the first entry is shown

savefig='[path/]<prefix>.<extension>' Will create a number of files with the charts.
The files will be saved location with name <path>/<prefix><variable name>.<extension>
The extension determines the format of the saved file. pdf, svg and png are the most common extensions.

!dir testgraph\
# fixed_alternative = mpak.fix(alternative,'PAKGGEXPCAPTCN PAKGGEXPGNFSCN PAKGGEXPOTHRCN PAKGGEXPTRNSCN',2023,2035)
fixed_alternative = mpak.fix(alternative,'PAKGGEXPCAPTCN ',2023,2035)
result_fixed_expenditure = mpak(fixed_alternative,2020,2035,keep='Taxes on Goods and Services up, expenditure fixed',silent=0,first_test=60) # simulates the model 
mpak.fix_dummy_fixed
mpak['PAKNYGDPMKTPCN PAKNYGDPMKTPKN PAKGGEXPTOTLCN PAKGGREVTOTLCN PAKNECONGOVTKN']
mpak.keep_solutions.keys()
with mpak.keepswitch(scenarios='Taxes on Goods and Services up by 1 pct of GDP in 2023|Taxes on Goods and Services up, expenditure fixed'):
    mpak.keep_plot('PAKNYGDPMKTPCN PAKNYGDPMKTPKN PAKGGEXPTOTLCN PAKGGREVTOTLCN PAKNECONGOVTKN',diff=1,showtype='level',legend=0);